/**
 * Slab 相关数据结构体的定义。
 */

#ifndef _AHAMOLETT_SLAB_TYPES_H_
#define _AHAMOLETT_SLAB_TYPES_H_

#include <cds/list.h>
#include <mm/flags_opt.h>

/// 包含一些暂时不方便在用户态中实现的功能，在实际移植的时候需要进行替换。
#include "../stubs.h"

/** 
 * @brief Slab 描述符结构体，用于表示一个 Slab 分配器。 
 */
struct kmem_cache {
    /* 储存该 Slab 描述符内所有 Slab 对象的链表。 */
    struct list_head full_list; /// 储存全部被分配的 Slab 对象的链表。
    struct list_head partial_list;  /// 储存部分被分配的 Slab 对象的链表。
    struct list_head empty_list;    /// 储存完全空闲的 Slab 对象的链表。
    unsigned long full_count;   /// 当前 Slab 描述符中全部被分配的 Slab 对象的个数。
    unsigned long partial_count;    /// 当前 Slab 描述符中部分被分配的 Slab 对象的个数。
    unsigned long empty_count;  /// 当前 Slab 描述符中完全空闲的 Slab 对象的个数。
    
    /// 当前 Slab 描述符允许存在的空闲 object 对象的上限，当前 Slab 描述符允许存在的空闲
    /// object 对象的上限，若当前 Slab 描述符中的空闲 object 数量超过这个上限，会尝试通过
    /// 释放 Slab 描述符来满足该上限。
    unsigned long free_limit;

    /* 属于该 Slab 描述符所有 Slab 对象共同的属性。 */
    size_t size;    /// 该 Slab 里单个 object 对齐后所占的内存大小。
    size_t alignment;   /// 该 Slab 里的 object 对齐的大小。 
    size_t objs_offset;  /// 为满足对齐条件，第一个内存对象在复合页内的偏移。
    unsigned long objs_each;    /// 每个 Slab 对象所拥有的 object 总数。
    unsigned long page_order;   /// 为 Slab 对象分配内存页时给定的阶数。
    char *name; /// Slab 描述符的名称，一个字符串。

    /* 对该 Slab 描述符所有 object 的信息。 */
    unsigned long objs_total;   /// 该 Slab 描述符中所有 object 的总数。
    unsigned long free_total;   /// 该 Slab 描述符中空闲 object 的总数。

    /* Slab 描述符的状态字。 */
    unsigned long flags;

    /* Slab 描述符的自旋锁。 */
    struct spinlock_t lock;
};

enum KMEM_CACHE_FLAGS {
    KMEM_FLAG_VALID,        /// 代表对应的描述符为有效的。
    KMEM_FLAG_STATIC_CACHE, /// 代表对应描述符为静态的，不可被销毁。
    KMEM_FLAG_NORMAL,       /// slab 对象的 freelist 位于剩余空间内。
    KMEM_FLAG_OFF_FREELIST, /// slab 对象的 freelist 位于一块单独分配的空间内。
    KMEM_FLAG_OBJ_FREELIST, /// slab 对象的 freelist 位于其中最后一个对象中。 
};

/* 对 Slab 描述符状态字各个位的操作。 */
#define DEFINE_KMEM_FLAG_BIT(name, bit) \
    DEFINE_FLAG_BIT(struct kmem_cache, flags, Kmem, name, bit)

DEFINE_KMEM_FLAG_BIT(Valid, KMEM_FLAG_VALID)
DEFINE_KMEM_FLAG_BIT(StaticCache, KMEM_FLAG_STATIC_CACHE)
DEFINE_KMEM_FLAG_BIT(NormalFreelist, KMEM_FLAG_NORMAL)
DEFINE_KMEM_FLAG_BIT(OffFreelist, KMEM_FLAG_OFF_FREELIST)
DEFINE_KMEM_FLAG_BIT(ObjFreelist, KMEM_FLAG_OBJ_FREELIST)

#endif

